#ifndef RTBYTESTREAM_H
#define RTBYTESTREAM_H

#include "RtDebug.h"

template <class BlockType, class ConvertorType>
class CRtByteStreamT
{
	enum { STRING_LEN_MAX = 32767 };
public:
	CRtByteStreamT(BlockType &aBlock)
		: m_Block(aBlock)
		, m_ResultRead(RT_OK)
		, m_ResultWrite(RT_OK)
	{
	}

	CRtByteStreamT& operator<<(char c)
	{
		Write(&c, sizeof(char));
		return *this;
	}

	CRtByteStreamT& operator<<(unsigned char c)
	{
		Write(&c, sizeof(unsigned char));
		return *this;
	}

	CRtByteStreamT& operator<<(SHORT n)
	{
		return *this << (WORD)n;
	}

	CRtByteStreamT& operator<<(WORD n)
	{
		ConvertorType::Swap(n);
		Write(&n, sizeof(WORD));
		return *this;
	}

	CRtByteStreamT& operator<<(INT n)
	{
		return *this << (UINT)n;
	}

	CRtByteStreamT& operator<<(UINT n)
	{
		ConvertorType::Swap(n);
		Write(&n, sizeof(UINT));
		return *this;
		//return *this << (DWORD)n;
	}

#ifdef WIN32
	CRtByteStreamT& operator<<(LONG n)
	{
//		return *this << (DWORD)n;
		return *this << (UINT)n;
	}

	CRtByteStreamT& operator<<(DWORD n)
	{
		return *this << (UINT)n;
//		ConvertorType::Swap(n);
//		Write(&n, sizeof(DWORD));
//		return *this;
	}
#endif
	/*CRtByteStreamT& operator<<(float n)
	{
		ConvertorType::Swap(n);
		Write(&n, sizeof(float));
		return *this;
	}

	CRtByteStreamT& operator<<(double n)
	{
		ConvertorType::Swap(n);
		Write(&n, sizeof(double));
		return *this;
	}*/
	CRtByteStreamT& operator<<(LONGLONG n)
	{
		ConvertorType::Swap(n);
		Write(&n, sizeof(LONGLONG));
		return *this;
	}

	CRtByteStreamT& operator<<(const CRtString &str)
	{
		return WriteString(str.c_str(), str.length());
	}

	CRtByteStreamT& operator<<(const char *str)
	{
		WORD len = 0;
		if (str)
			len = strlen(str);
		return WriteString(str, len);
	}

	CRtByteStreamT& WriteString(const char *str, DWORD ll)
	{
		WORD len = static_cast<WORD>(ll);
		RT_ASSERTE(len < STRING_LEN_MAX);
		if (len >= STRING_LEN_MAX) {
			RT_ERROR_TRACE_THIS("CRtByteStreamT::WriteString, too long, len=" << len);
			m_ResultWrite = RT_ERROR_UNEXPECTED;
			return *this;
		}

		(*this) << len;
		if (len > 0)
			Write(str, len);
		return *this;
	}

	CRtByteStreamT& WriteStringWith4BytesLength(const CRtString &str)
	{
		return WriteStringWith4BytesLength(str.c_str(), str.length());
	}

	CRtByteStreamT& WriteStringWith4BytesLength(const char *str, DWORD ll)
	{
		(*this) << ll;
		if (ll > 0)
			Write(str, ll);
		return *this;
	}

	CRtByteStreamT& operator>>(char& c)
	{
		Read(&c, sizeof(char));
		return *this;
	}

	CRtByteStreamT& operator>>(unsigned char& c)
	{
		Read(&c, sizeof(unsigned char));
		return *this;
	}

	CRtByteStreamT& operator>>(WORD& n)
	{
		Read(&n, sizeof(WORD));
		ConvertorType::Swap(n);
		return *this;
	}

	CRtByteStreamT& operator>>(SHORT& n)
	{
		return *this >> (WORD&)n;
	}

	CRtByteStreamT& operator>>(INT& n)
	{
		return *this >> (UINT&)n;
	}

	CRtByteStreamT& operator>>(UINT& n)
	{
		Read(&n, sizeof(UINT));
		ConvertorType::Swap(n);
		return *this;
		//return *this >> (DWORD&)n;
	}
#ifdef WIN32
	CRtByteStreamT& operator>>(LONG& n)
	{
		return *this >> (UINT&)n;
		//return *this >> (DWORD&)n;
	}

	CRtByteStreamT& operator>>(DWORD& n)
	{
		return *this >> (UINT&)n;
//		Read(&n, sizeof(DWORD));
//		ConvertorType::Swap(n);
//		return *this;
	}
#endif
	/*CRtByteStreamT& operator>>(float& n)
	{
		Read(&n, sizeof(float));
		ConvertorType::Swap(n);
		return *this;
	}

	CRtByteStreamT& operator>>(double& n)
	{
		Read(&n, sizeof(double));
		ConvertorType::Swap(n);
		return *this;
	}*/

	CRtByteStreamT& operator>>(LONGLONG& n )
	{
		Read(&n, sizeof(LONGLONG));
		ConvertorType::Swap(n);
		return *this;	
	}

	CRtByteStreamT& operator>>(CRtString& str)
	{
		WORD len = 0;
		(*this) >> len;
		RT_ASSERTE(len < STRING_LEN_MAX);
		if (len >= STRING_LEN_MAX) {
			RT_ERROR_TRACE_THIS("CRtByteStreamT::operator>>CRtString, too long, len=" << len);
			m_ResultRead = RT_ERROR_UNEXPECTED;
			return *this;
		}

		str.resize(0);
		if (len > 0) {
			str.resize(len);
			Read(const_cast<char*>(str.data()), len);
		}
		return *this;
	}

	CRtByteStreamT& ReadStringWith4BytesLength(CRtString& str)
	{
		DWORD len = 0;
		(*this) >> len;

		str.resize(0);
		if (len > 0) {
			str.resize(len);
			Read(const_cast<char*>(str.data()), len);
		}
		return *this;
	}
	
	CRtByteStreamT& Read(void *aDst, DWORD aCount)
	{
		if (RT_SUCCEEDED(m_ResultRead)) {
			DWORD ulRead = 0;
			m_ResultRead = m_Block.Read(aDst, aCount, &ulRead);
#ifdef RT_DEBUG
			if (RT_SUCCEEDED(m_ResultRead))
				RT_ASSERTE(ulRead == aCount);
#endif // RT_DEBUG
		}
		if (RT_FAILED(m_ResultRead)) {
			RT_ERROR_TRACE_THIS("CRtByteStreamT::Read, can't read. m_ResultRead=" << m_ResultRead);
		}
		return *this;
	}

	CRtByteStreamT& Write(const void *aDst, DWORD aCount)
	{
		if (RT_SUCCEEDED(m_ResultWrite)) {
			DWORD ulWritten = 0;
			m_ResultWrite = m_Block.Write(aDst, aCount, &ulWritten);
#ifdef RT_DEBUG
			if (RT_SUCCEEDED(m_ResultWrite))
				RT_ASSERTE(ulWritten == aCount);
#endif // RT_DEBUG
		}
		if (RT_FAILED(m_ResultWrite)) {
			RT_ERROR_TRACE_THIS("CRtByteStreamT::Write, can't write. m_ResultWrite=" << m_ResultWrite);
		}
		return *this;
	}
	
	BOOL IsGood()
	{
		if (RT_SUCCEEDED(m_ResultWrite) && RT_SUCCEEDED(m_ResultRead))
			return TRUE;
		else
			return FALSE;
	}

public:
	static DWORD StringStreamLength(const CRtString& str)
	{
		return (sizeof(WORD) + str.length());
	}
private:
	BlockType &m_Block;
	RtResult m_ResultRead;
	RtResult m_ResultWrite;

	// Not support bool because its sizeof is not fixed.
	CRtByteStreamT& operator<<(bool n);
	CRtByteStreamT& operator>>(bool& n);

	// Not support long double.
	CRtByteStreamT& operator<<(long double n);
	CRtByteStreamT& operator>>(long double& n);
};

class CRtHostNetworkConvertorNormal
{
public:
	static void Swap(UINT &aHostLong)
	{
#ifdef RT_LITTLE_ENDIAN
		Swap4(&aHostLong, &aHostLong);
#endif // RT_LITTLE_ENDIAN
	}

	static void Swap(WORD &aHostShort)
	{
#ifdef RT_LITTLE_ENDIAN
		Swap2(&aHostShort, &aHostShort);
#endif // RT_LITTLE_ENDIAN
	}
	/*static void Swap(float &aHostFloat)
	{
#ifdef RT_LITTLE_ENDIAN
		Swap4(&aHostFloat, &aHostFloat);
#endif // RT_LITTLE_ENDIAN
	}

	static void Swap(double &aHostDouble)
	{
#ifdef RT_LITTLE_ENDIAN
		Swap8(&aHostDouble, &aHostDouble);
#endif // RT_LITTLE_ENDIAN
	}*/

	// mainly copied from ACE_CDR
	static void Swap2(const void *orig, void* target)
	{
		register WORD usrc = 
			* reinterpret_cast<const WORD*>(orig);
		register WORD* udst = 
			reinterpret_cast<WORD*>(target);
		*udst = (usrc << 8) | (usrc >> 8);
	}

	static void Swap4(const void* orig, void* target)
	{
		register DWORD x = 
			* reinterpret_cast<const DWORD*>(orig);
		x = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
		* reinterpret_cast<DWORD*>(target) = x;
	}

	static void Swap8(const void* orig, void* target)
	{
		register DWORD x = 
			* reinterpret_cast<const DWORD*>(orig);
		register DWORD y = 
			* reinterpret_cast<const DWORD*>(static_cast<const char*>(orig) + 4);
		x = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
		y = (y << 24) | ((y & 0xff00) << 8) | ((y & 0xff0000) >> 8) | (y >> 24);
		* reinterpret_cast<DWORD*>(target) = y;
		* reinterpret_cast<DWORD*>(static_cast<char*>(target) + 4) = x;
	}
};

class CRtHostConvertorIntelFirst
{
public:
	static void Swap(LONGLONG &aHostLongLong)
	{
#ifndef RT_LITTLE_ENDIAN
		CRtHostNetworkConvertorNormal::Swap8(&aHostLongLong, &aHostLongLong);
#endif // RT_LITTLE_ENDIAN
	}
	static void Swap(UINT &aHostLong)
	{
#ifndef RT_LITTLE_ENDIAN
		CRtHostNetworkConvertorNormal::Swap4(&aHostLong, &aHostLong);
#endif // RT_LITTLE_ENDIAN
	}

	static void Swap(WORD &aHostShort)
	{
#ifndef RT_LITTLE_ENDIAN
		CRtHostNetworkConvertorNormal::Swap2(&aHostShort, &aHostShort);
#endif // RT_LITTLE_ENDIAN
	}

	/*static void Swap(float &aHostFloat)
	{
#ifndef RT_LITTLE_ENDIAN
		CRtHostNetworkConvertorNormal::Swap4(&aHostFloat, &aHostFloat);
#endif // RT_LITTLE_ENDIAN
	}

	static void Swap(double &aHostDouble)
	{
#ifndef RT_LITTLE_ENDIAN
		CRtHostNetworkConvertorNormal::Swap8(&aHostDouble, &aHostDouble);
#endif // RT_LITTLE_ENDIAN
	}*/
};

class CRtHostNetworkConvertorNull
{
public:
	static void Swap(UINT &aHostLong)
	{
	}

	static void Swap(WORD &aHostShort)
	{
	}

	/*static void Swap(float &aHostFloat)
	{
	}

	static void Swap(double &aHostDouble)
	{
	}*/
};

#include "RtMessageBlock.h"

typedef CRtByteStreamT<CRtMessageBlock, CRtHostNetworkConvertorNormal> CRtByteStreamNetwork;
typedef CRtByteStreamT<CRtMessageBlock, CRtHostNetworkConvertorNull> CRtByteStreamMemory;
typedef CRtByteStreamT<CRtMessageBlock, CRtHostConvertorIntelFirst> CRtByteStreamIntel;

#endif // !RTBYTESTREAM_H
